/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.admin.addins;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.extensions.ajax.markup.html.form.upload.UploadProgressBar;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.target.resource.ResourceStreamRequestTarget;
import org.apache.wicket.util.resource.FileResourceStream;
import org.gidoo.cms.GidooCMS;
import org.gidoo.cms.admin.AdminPage;
import org.gidoo.cms.login.GidooCMSSession;
import org.gidoo.wickettools.MessageBox;
import org.gidoo.wickettools.IMessageBoxResultReceiver;
import org.gidoo.wickettools.MessageBox.MessageBoxResult;

/**
 *
 * @author thomas
 */
public class BackupPanel extends AddInPanel
{

  private Form formImport;
  private Form formExport;
  private FileUploadField fileImport;
  private Button btImport;
  private Button btExport;
  
  
  
  private AdminPage adminPage;
  
  private File lastFileUploaded;
  
  public final int BACKUP_FILE_VERSION = 4;
  
  public BackupPanel(String id, AdminPage adminPage)
  {
    super(id);
    this.adminPage = adminPage;
    
    lastFileUploaded = null;
    
    formImport = new Form("formImport");
        
    fileImport = new FileUploadField("fileImport");
    fileImport.setModel(new Model<FileUpload>());
    formImport.add(fileImport);
    btImport = new Button("btImport")
    {

      @Override
      public void onSubmit()
      {
        importCMS();
      }
    };    
    btImport.setModel(new Model(getString("load")));
    formImport.add(btImport);
    
    formImport.add(new UploadProgressBar("uploadProgress", formImport));
    
    add(formImport);
    
    formExport = new Form("formExport");
    btExport = new Button("btExport") 
    {

      @Override
      public void onSubmit()
      {
        exportCMS();
      }
      
    };
    btExport.setModel(new Model(getString("exportnow")));
    formExport.add(btExport);
    
    add(formExport);
  }
  
  private void importCMS()
  {
    // print warning
    MessageBox msg = new MessageBox(getString("importwarningtitle"), getString("importwarning"),
      true, MessageBox.MessageBoxButtons.YES_NO, adminPage, 
      new IMessageBoxResultReceiver() 
      {
        public void receiveMessageBoxResult(MessageBoxResult result)
        {
          if(result == MessageBoxResult.YES)
          {
            if(lastFileUploaded != null)
            {
              if(importCMSFromFile(lastFileUploaded))
              {
                // logout since our user might not exist any longer
                ((GidooCMSSession) getSession()).signOut();
                GidooCMS cms = (GidooCMS) getApplication();
                setResponsePage(cms.CMS_CONFIGURATION.getCMSMainPage());
              }
            }
            else
            {
              error(getString("nullupload"));
            }
          }
        }
      }
    );
    
    FileUpload up = fileImport.getFileUpload();
    if(up != null)
    {
      try
      {
        lastFileUploaded = up.writeToTempFile();
        setResponsePage(msg);
      }
      catch (IOException ex)
      {
        error(getString("ioerror"));
        Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
      }
      
    }
    else
    {
      error(getString("nofile"));
    }
    
  }
  
  private boolean importCMSFromFile(File file)
  {
    if(file != null && file.isFile() && file.canRead())
    {
      try
      {
        ZipFile zf = new ZipFile(file);
        // check version
        ZipEntry zeVersion = zf.getEntry("version");
        ZipEntry zeDrafts = zf.getEntry("drafts.xml");
        ZipEntry zeUsers = zf.getEntry("users.xml");
        ZipEntry zeSections = zf.getEntry("sections.xml");
        ZipEntry zePrivateDrafts = zf.getEntry("private_drafts.xml");
        
        if(zeVersion == null || zeDrafts == null || zeUsers == null
          || zeSections == null)
        {
          error(getString("structerror"));
        }
        else
        {
          ObjectInputStream in = new ObjectInputStream(zf.getInputStream(zeVersion));
          int version = in.readInt();
          in.close();
          
          if(version == 1 || version == 2 || version == 3 || version == 4)
          {
            Session session = ((GidooCMSSession) getSession()).getJcrSession();
      
            InputStream draftIn = zf.getInputStream(zeDrafts);
            InputStream usersIn = zf.getInputStream(zeUsers);
            InputStream sectionsIn = zf.getInputStream(zeSections);
            InputStream privateDraftsIn = null;
            if(zePrivateDrafts != null)
            {
              privateDraftsIn = zf.getInputStream(zePrivateDrafts);
            }
            // delete old nodes
            Node rootNode = session.getRootNode();
            
            if(rootNode.hasNode("drafts"))
              rootNode.getNode("drafts").remove();
            if(rootNode.hasNode("users"))
              rootNode.getNode("users").remove();
            if(rootNode.hasNode("sections"))
              rootNode.getNode("sections").remove();
            if(rootNode.hasNode("private_drafts"))
              rootNode.getNode("private_drafts").remove();
            
            // add "new" nodes
            session.importXML("/", draftIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            session.importXML("/", usersIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            session.importXML("/", sectionsIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            if(privateDraftsIn == null)
            {
              rootNode.addNode("private_drafts");
            }
            else
            {
              session.importXML("/", privateDraftsIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            }
            
            session.save();
            
            return true;
          }
          else
          {
            error(getString("versionerror"));
          }
        }
      }
      catch(RepositoryException ex)
      {
        Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
        error(getString("jcrerror"));
      } 
      catch (IOException ex)
      {
        Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
        error(getString("ioerror"));
      }
    }
    else
    {
      error(getString("ioerror"));
    }
      
    return false;
  }
  
  private void exportCMS()
  {
    try
    {      
      Date backupTime = new Date();
      
      Session session = ((GidooCMSSession) getSession()).getJcrSession();
      
      // zip it together to one file
      File tmpZipFile = File.createTempFile("cmsBackupTmp", ".zip");
      tmpZipFile.deleteOnExit();
      ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(tmpZipFile));
      
      // write content and user data
      ZipEntry zeVersion = new ZipEntry("version");
      zout.putNextEntry(zeVersion);  
      ObjectOutputStream o = new ObjectOutputStream(zout);
      o.writeInt(BACKUP_FILE_VERSION);
      o.flush();
      zout.closeEntry();
      
      ZipEntry zeTmp = new ZipEntry("drafts.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/drafts", zout, false, false);
      zout.closeEntry();
     
      zeTmp = new ZipEntry("private_drafts.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/private_drafts", zout, false, false);
      zout.closeEntry();
      
      zeTmp = new ZipEntry("users.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/users", zout, false, false);
      zout.closeEntry();
      
      zeTmp = new ZipEntry("sections.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/sections", zout, false, false);
      zout.closeEntry();
      
      zout.close();
      
      DateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
      
      // return as request (file)
      RequestCycle.get().setRequestTarget(
        new ResourceStreamRequestTarget(
          new FileResourceStream(tmpZipFile) 
          {
            @Override
            public String getContentType()
            {
              return "application/zip";
            }          
          }, "backupCMS_" + df.format(backupTime).replaceAll(" ", "_") + ".zip"
      ));
      
    }  
    catch(IOException ex)
    {
      Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("ioerror"));
    }
    catch (RepositoryException ex)
    {
      Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
    
    
  }
  
}
